from pentester.hosts.metasploit import MetaSploitLocal, MetaSploitRemote
from pentester.hosts.models import Configuration
from pentester.hosts.views import createMenu
from pentester.worker.models import Logs, Session
from django.shortcuts import render_to_response
from django.http import HttpResponse,HttpResponseRedirect
from pentester.hosts.ifconfig import IFConfig
from time import sleep
import re

def getcfgobj():
    """
    Internal method used for getting tool configuration (mainly MetaSploit parameters)
    from the Configuration model. Returns Configuration objects if exist, or renders
    error page with proper alert.
    """
    try:
        cfgobj = Configuration.objects.get()
    except Configuration.DoesNotExist:
        return render_to_response("error.html",
                         { 'value' : 'Set Metasploit Framework Path in Configuration'}
                         )
    return cfgobj

def scan(request):
    """
    View that performs a scan for IP services on remote hosts contained in IP subnet
    matching current subnet set on the particular network interface (this one specified
    in request by POST['iface']
    """
    cfgobj = getcfgobj()
    iface = request.POST['iface']
    m = MetaSploitLocal(cfgobj.msfpath)
    m.connect(login=cfgobj.msfdb_login, password=cfgobj.msfdb_pass, dbname=cfgobj.msfdb_name, hostname=cfgobj.msfdb_host, port=cfgobj.msfdb_port)
    network = "%s/%s" % ( IFConfig.get_ip_address(iface), IFConfig.get_netmask(iface))
    ret =  m.scan(network)
    # joins the returnet list of lines
    # to one string, and save in Logs model
    scanlog = Logs(eventType='S', eventText='\n'.join(ret))
    scanlog.save()
    return HttpResponseRedirect("/services")

def netscan(request):
    """
    Performs an NMAP network scan on specified IP network (passed through POST['address']
    argument). Scan is run by executing db_nmap command of the metasploit wrapper for NMAP.
    Results are collected to the temporary XML file (-oX option in nmap), and then
    parsed by MetaSploit Framework to the SQL database format.
    """
    cfgobj = getcfgobj()
    if cfgobj.msftype == 'R':
        m = MetaSploitRemote(cfgobj.msfaddr, cfgobj.msfport)
    elif cfgobj.msftype == 'L':
        m = MetaSploitLocal(cfgobj.msfpath)
        m.connect(login=cfgobj.msfdb_login, password=cfgobj.msfdb_pass, dbname=cfgobj.msfdb_name, hostname=cfgobj.msfdb_host, port=cfgobj.msfdb_port)
    if isValidNetwork(request.POST['adddress']):
        ret = m.scan(request.POST['address'])
        scanlog = Logs(eventType='S', eventText='\n'.join(ret))
        scanlog.save()
    return HttpResponseRedirect("/services")

def isValidNetwork(net):
    import re
    """
    Checks given string for proper syntax of network address
    given in CIDR format (e.g. 172.30.0.1/24).
    Returns True if 'net' has proper syntax. Otherwise returns False.
    """
    if re.match("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$",net):
        return True
    else:
        return False
def exploit(request):
    """
    Starts exploitation of hosts. Hosts addresses is retrieved from the 
    database (prior filled manually or by network scan). Results are collected
    as text and inserted to the Logs table in the database. Additionaly
    this method runs listing of currently opened sessions (after MetaSploit
    exploitation), parses it, and inserts tuples (lhost,lport,rhost,rport)
    describing opened sessions to the database.
    """
    cfgobj = getcfgobj()
    if cfgobj.msftype == 'R':
        m = MetaSploitRemote(cfgobj.msfaddr, cfgobj.msfport)
    elif cfgobj.msftype == 'L':
        m = MetaSploitLocal(cfgobj.msfpath)
    
    # cleanup previous opened sessions    
    for session in Session.objects.all():
        session.delete()
    m.connect(login=cfgobj.msfdb_login, password=cfgobj.msfdb_pass, dbname=cfgobj.msfdb_name, hostname=cfgobj.msfdb_host, port=cfgobj.msfdb_port)
    #TODO: add exclude and include mode
    ret = m.exploit()
    exlog = Logs(eventType='E', eventText='\n'.join(ret))
    exlog.save()
    sleep(4)
    m.flush()
    p = re.compile("^  \d+   Command shell  (\d+\.\d+\.\d+\.\d+):(\d+) -> (\d+\.\d+\.\d+\.\d+):(\d+)")
    lines = m.listsessions()
    for line in lines:
        match = p.match(line)
        if match:
            (lhost, lport, rhost, rport) = match.groups()
            session = Session(lhost=lhost,lport=lport,rhost=rhost,rport=rport)
            session.save()
    return HttpResponseRedirect("/results")

def clearlogs(request):
    """
        Deletes all Log objects from database.
    """
    logs = Logs.objects.all()
    count = 0
    for log in logs:
        count += 1
        log.delete()
    sessions = Session.objects.all()
    for ses in sessions:
        ses.delete()
    return render_to_response("logs_cleared.html", { 'count' : count, 'menuitems' : createMenu('logs')  } )


def results(request):
    """
    Processes list of currently opened sessions (successfully exploited hosts),
    by taking their rhost value, and linking them to unordered list of IP
    addresses of remote hosts. Afterwards list is passed to proper template
    for display.
    """
    return render_to_response("sess_list.html",
                 { 'menuitems' : createMenu('results'),
                   'hosts' : list(set(map(lambda x: x.rhost, Session.objects.all()))) }
                 ) 